//  Copyright (c) 2020-present,  INSPUR Co, Ltd.  All rights reserved.
// This source code is licensed under Apache 2.0 License.

// liliupeng@inspur.com

#include "util/testharness.h"
#include <chrono>
#include <iostream>
#include "pure_mem/key_index/abstract_void_ref.h"
#include "pure_mem/key_index/tree_void_ref.h"
#include "pure_mem/key_index/tree_void_ref2.h"
#include <pure_mem/memoryblock/memory_arena/memory_arena.h>
#include <string>

namespace rocksdb {

Slice genMVCCKey1(int s) {
  std::string key = "test_" + std::to_string(s);
  uint32_t keySize = key.size() + 1;
  char* ret = new char[keySize];
  memset(ret, '\0', keySize);
  memcpy(ret, key.data(), key.size());
  return {ret, keySize};
}

Slice genInternalKey(Slice& key, SequenceNumber seq, ValueType t, char* buf){
  size_t  key_size = key.size();
  char* p = buf;
  memcpy(p, key.data(), key_size);
  p += key_size;
  uint64_t packed = PackSequenceAndType(seq, t);
  EncodeFixed64(p, packed);
  return {buf, key_size + 8};
}

typedef InlineUserKeyIndex<const MemTableRep::KeyComparator &> ArtTree;
class ARTRefExample {
public:
  ArtTree* list_;
  int refType_;
public:
  ARTRefExample(MemArena::KeyComparator mkey_cmp, int refType) : refType_(refType) {
    switch (refType){
    case 1:
      list_ = new ArtTree(mkey_cmp, ART_ROWEX, ITreeVoidRef::RefType::REFTYPE2);
      break;
    case 2:
      list_ = new ArtTree(mkey_cmp, ART_ROWEX, ITreeVoidRef::RefType::REFTYPE1);
      break;
    default:
      assert(false);
      break;
    }

  }

  ~ARTRefExample() {
    auto iter = list_->GetIterator();
    iter->SeekToFirst();
    while(iter->Valid()){
      delete[] iter->key();
      delete iter->node();
      iter->Next();
    }
  }


  void testRef() {
    std::cout << "test case: different Ref!" << std::endl;

    char tmp[1000];
    memset(tmp, 70, 1000);
    Slice value = Slice(tmp, 1000);
    SequenceNumber seq = 100000;
    for(int i = 0; i < 1000; i++){
      Slice key = Slice(genMVCCKey1(seq++));
      VersionNode *node = genNode(1, key, value, seq, kTypeValue);
      bool ok = list_->Insert(reinterpret_cast<const char *>(node));
      assert(ok);
    }
  }

  VersionNode *genNode(int type, const Slice &key, const Slice &value,
                       SequenceNumber seq, ValueType valuetype) {
    switch (type) {
    case 1:{
      auto* cur = new EncodedVersionNode();

      size_t key_size = key.size();
      size_t val_size = value.size();
      size_t interkey_size = key_size + 8;
      size_t encoded_len = VarintLength(interkey_size) + interkey_size +
                           VarintLength(val_size) + val_size;

      char* buf = new char[encoded_len];
      VersionNode::Encode(key, value, seq, valuetype, buf);
      cur->SetNext(nullptr);
      cur->SetPrev(nullptr);
      bool ok = cur->CASSetKey(nullptr, buf);
      assert(ok);
      return cur;
    }
    case 2:
      return new UncodedVersionNode(key, value, seq, valuetype);

    default:
      break;
    }
    return nullptr;
  }

};

class RefTest : public testing::Test, public testing::WithParamInterface<int> {
public:
};

INSTANTIATE_TEST_CASE_P(artTreType, RefTest,testing::Values(1, 2));

TEST_P(RefTest, testRef) {
  int refType = GetParam();
  InternalKeyComparator cmp(BytewiseComparator());
  MemArena::KeyComparator mkey_cmp(cmp);
  ARTRefExample artExm(mkey_cmp, refType);
  artExm.testRef();
}


} // namespace rocksdb

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
  system("pause");
}
